package service

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	wechat "gitee.com/quantum-force/wxopen-api"
	"github.com/nsqio/go-nsq"
	"open/internal/model"
	"open/internal/model/event"
	"open/internal/model/field"
	"open/internal/types"
	"open/pkg/log"
)

// CommitAuditWechatMini 提交微信小程序审核
func (s *Service) CommitAuditWechatMini(ctx context.Context, appID string, biz json.RawMessage) error {
	req := &wechat.SubmitAuditRequest{}
	if err := json.Unmarshal(biz, req); err != nil {
		return err
	}
	auditID, err := s.dao.CommitAuditWechatMini(ctx, appID, req)
	if err != nil {
		if wechatErr, ok := err.(*wechat.ErrorResponse); ok {
			switch wechatErr.Code {
			case 85009:
				err = nil
			case 85085:
				return s.innerRejectWithReason(ctx, appID, types.Wechat, "当前审核额度达到上限，请稍后重试")
			default:
				return s.innerRejectWithReason(ctx, appID, types.Wechat, fmt.Sprintf("%d:%s", wechatErr.Code, wechatErr.Message))
			}
		}
		if err != nil {
			return err
		}
	}

	logger := log.FromContext(ctx)
	logger.Infof("app_id:%s, CommitAuditWechatMini get return auditID:%s", appID, auditID)

	if err := s.dao.Transaction(ctx, func(ctx context.Context) error {
		appVersion, err := s.dao.LockAppVersion(ctx, appID, types.Wechat)
		if err != nil {
			return err
		}
		appVersion.Stage = types.StageAuditing
		if err = s.dao.SaveAppVersion(ctx, appVersion); err != nil {
			return err
		}
		return nil
	}); err != nil {
		return err
	}
	return nil
}

// HandleTaskSyncWechatPubTemplate 同步微信订阅消息模版
func (s *Service) HandleTaskSyncWechatPubTemplate(ctx context.Context, msg *nsq.Message) (err error) {
	req := new(event.TaskSendWechatPubMessage)
	if err := json.Unmarshal(msg.Body, req); err != nil {
		return err
	}
	err = s.handleTask(ctx, req.JobID, func() error {
		if err = s.dao.SyncWechatPubTemplate(ctx, req.AppID); err != nil {
			return err
		}
		return nil
	})
	return
}

// CommitWechatMini 提交微信小程序
func (s *Service) CommitWechatMini(ctx context.Context, appID string, biz json.RawMessage) error {
	// Step1: 设置服务器域名
	if err := s.dao.SetWechatDomains(ctx, appID); err != nil {
		return err
	}
	// Step2: 设置业务域名
	if err := s.dao.SetWechatWebViewDomains(ctx, appID); err != nil {
		return err
	}
	// Step3: 申请插件
	if err := s.dao.ApplyWechatPlugins(ctx, appID); err != nil {
		if wechatErr, ok := err.(*wechat.ErrorResponse); ok {
			// 判定是否因为未勾选插件管理权限
			if wechatErr.Code == 61007 {
				return s.innerRejectWithReason(ctx, appID, types.Wechat, "当前微信小程序未授权插件管理权限，请重新授权后再次发起审核")
			}
		}
		return err
	}
	// Step4: 构建请求req
	req, err := s.dao.BuildWechatCommitRequest(ctx, appID, biz)
	if err != nil {
		return err
	}
	// Step5: 提交代码
	if err := s.dao.CommitWechatMini(ctx, appID, req); err != nil {
		return err
	}

	if err := s.dao.Transaction(ctx, func(ctx context.Context) error {
		appVersion, err := s.dao.GetAppVersion(ctx, appID, types.Wechat)
		if err != nil {
			return err
		}

		// added 2022-02-24 更新 app_version.stage => StageCommitted
		appVersion.Stage = types.StageCommitted
		if err = s.dao.SaveAppVersion(ctx, appVersion); err != nil {
			return err
		}

		jobData, _ := json.Marshal(req)
		// Step6: 新建提交审核任务
		schedule := &model.Schedule{
			RefID:     appVersion.ID,
			JobType:   types.TaskCommitAudit,
			JobData:   field.JSON(jobData),
			JobStatus: types.ScheduleTaskInit,
		}
		if err := s.dao.CreateSchedule(ctx, schedule); err != nil {
			return err
		}
		// Step7: 发送事件
		if err := s.dao.TxSend(ctx, event.TaskCommitAudit{
			AppID:     appID,
			Platform:  types.Wechat,
			JobID:     schedule.ID,
			Biz:       jobData,
			Timestamp: time.Now().Unix(),
		}); err != nil {
			return err
		}
		return nil
	}); err != nil {
		return err
	}
	return nil
}

// ReleaseWechatMini 发布微信小程序
func (s *Service) ReleaseWechatMini(ctx context.Context, appID string) error {
	if err := s.dao.ReleaseWechatMini(ctx, appID); err != nil {
		if wechatError, ok := err.(*wechat.ErrorResponse); ok {
			if wechatError.Code == 85052 {
				// 重复发布
				err = nil
			}
		}
		if err != nil {
			return err
		}
	}
	if err := s.dao.Transaction(ctx, func(ctx context.Context) error {
		appVersion, err := s.dao.LockAppVersion(ctx, appID, types.Wechat)
		if err != nil {
			return err
		}
		appVersion.Stage = types.StageReleased
		appVersion.Status = types.StageReleased
		appVersion.ReleaseVersion = appVersion.AuditVersion
		appVersion.AuditVersion = ""
		if err = s.dao.SaveAppVersion(ctx, appVersion); err != nil {
			return err
		}
		if err = s.dao.CreateVersionLog(ctx, &model.MiniAppVersionLog{
			VersionID: appVersion.ID,
			Version:   appVersion.ReleaseVersion,
		}); err != nil {
			return err
		}
		return nil
	}); err != nil {
		return err
	}
	return nil
}

// UpdateWechatMiniStatus 更新微信小程序状态
func (s *Service) UpdateWechatMiniStatus(ctx context.Context, appID string) error {
	auditStatus, err := s.dao.GetLatestWechatAuditStatus(ctx, appID)
	if err != nil {
		return err
	}
	var stage, status, reason string
	switch auditStatus.Status {
	case 0:
		stage = types.StageWaitRelease
		status = types.StatusReleased
	case 1:
		stage = types.StageAuditReject
		status = types.StatusReject
		reason = auditStatus.Reason
	case 2:
		stage = types.StageAuditing
		status = types.StatusAuditing
	case 3:
		stage = types.StageAuditWithdrawn
		status = types.StatusAuditing
	default:
		return fmt.Errorf("unknown wechat audit stage: %s", err)
	}
	if err := s.dao.Transaction(ctx, func(ctx context.Context) error {
		appVersion, err := s.dao.LockAppVersion(ctx, appID, types.Wechat)
		if err != nil {
			return err
		}
		appVersion.Stage = stage
		appVersion.Status = status
		appVersion.RejectReason = reason
		if err = s.dao.SaveAppVersion(ctx, appVersion); err != nil {
			return err
		}
		return nil
	}); err != nil {
		return err
	}
	return nil
}
